#include "jeu.h"
#include <malloc.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>
#include <time.h>

    time_t time(time_t *tloc); //pour le  random


void jeuInit(jeu * j)
{
    int x, y, i_ennemi;

    terrainInit(&(j->t));
	persoInit(&(j->p), &(j->t));
    ensembleEnnemisInit(&(j->te),5);
    srand(time(NULL));
    for (i_ennemi=0; i_ennemi<(getNbEnnemis(&(j->te))); i_ennemi++)
    {

        do
        {
            x = rand()%getDimX(&j->t);

            y = rand()%getDimY(&j->t);





        }
        while  ((!caseValable(x,y,&(j->t))) || (dist(j,x,y)<8)) ;

        ennemisInit(&(j->te.tabEnnemis[i_ennemi]),x,y,passif ,1);


    }

}

float dist(jeu *j,int x,int y)//renvoie la distance  entre un point et le perso
{
    float distance;


   return distance=sqrt(pow(PgetPosX(&(j->p))-x,2)+pow(PgetPosY(&(j->p))-y,2) ) ;



}


void jeuLibere(jeu * j)
{
	terrainLibere(&(j->t));
}

terrain * jeuGetTerrain(jeu * j)
{
	return &(j->t);
}

personnage * jeuGetPersonnage(jeu * j)
{
	return &(j->p);
}

balle * jeuGetBalle(jeu * j)
{
	return &(j->b);
}

const terrain* jeuGetConstTerrain(const jeu* j)
{
	return &(j->t);
}


const personnage* jeuGetConstPersonnage(const jeu * j)
{
	return &(j->p);
}

const balle* jeuGetConstBalle(const jeu * j)
{
	return &(j->b);
}


void jeuActionClavier(jeu * j, const char touche)

{
	int i;
	switch(touche)
	{
		case 'g' : /*gauche : rotation*/
				i=getDirection(&(j->p));
				if(i==0)
				{
                    i=7;
				}
				else
                    i=(i-1);
                setDirection (&(j->p), i);
				break;
		case 'd' : /*droite : rotation*/
				i=getDirection(&(j->p));
				i=(i+1)%8;
                setDirection (&(j->p), i);
				break;
		case 'h' : /* haut : avance*/
				deplacementAvant(&(j->p) , &(j->t));
				break;
		case 'b' : /* bas : recule*/
				deplacementArriere(&(j->p) , &(j->t));
				break;
        case 't' : /*Espace = TIR */
                if(PgetNBmunition(&(j->p))!=0)
                {
                    balleInit(&(j->b), &(j->t), &(j->p));
                }
                setBalleTiree(&(j->p));
                break;


	}
}


void collision(jeu *j)
{
    int i;
    for (i=0;i<getNbEnnemis(&(j->te));i++) //pour chaque ennemis
    {
        if ((EgetPosX(&(j->te.tabEnnemis[i]))==PgetPosX(&(j->p))) && (EgetPosY(&(j->te.tabEnnemis[i]))==PgetPosY(&(j->p))))//collision avec personnage
        {
            int Xdepart = (j->t.dimX)/2;
            int Ydepart = (j->t.dimY)/2;
            if(!caseValable( Xdepart , Ydepart , &(j->t)))
            {
                j->t.ter[Xdepart][Ydepart]=' ';
            }

            setPVmoins(&(j->p));
            PsetPosition(&(j->p), &(j->t), Xdepart, Ydepart);
            setDirection(&(j->p), 0);
        }

        else if ((EgetPosX(&(j->te.tabEnnemis[i]))==BgetPosX(&(j->b))) && (EgetPosY(&(j->te.tabEnnemis[i]))==BgetPosY(&(j->b))))//collision avec balle
        {

            balleLibere(&(j->b));
            if (EgetPV(&(j->te.tabEnnemis[i]))==1)// Si l'ennemi a 1 PV, il meurt
            {
                setEtat(&(j->te.tabEnnemis[i]),mort);

            }
            else
            {
                 perdPVennemis(&(j->te.tabEnnemis[i]),1);
            }

        }
    }
}


int testFinJeu(jeu *j)
{
    int i;
    int compteurMort=0;
    for(i=0;i<j->te.nbEnnemis; i++)
    {
          if (getEtat(&(j->te.tabEnnemis[i]))==mort)
          compteurMort++;
    }

    if ((PgetPV(&(j->p))==0) || (compteurMort==getNbEnnemis(&(j->te))))
    {
        return 0;
    }

    else
    {
         return 1;
    }
}



void tir(jeu * j)
{


    int i = j->b.dir;
    int Xsuivant=j->b.posX +vecteur[i][0];
    int Ysuivant=j->b.posY + vecteur[i][1];

    if (caseValable(Xsuivant, Ysuivant, &(j->t)))
    {
        j->b.posX = Xsuivant;
        j->b.posY = Ysuivant;
        j->b.portee -= 1;
    }
    else
    {
        balleLibere(&(j->b));
    }
    if(j->b.portee<=0)
    balleLibere(&(j->b));
}

void jeuDeplacementennemis(jeu *j)
{


    int tx=j->t.dimX;
    int ty=j->t.dimY;
    int x,y;


    float **dist = (float **)malloc(sizeof(float *)*tx);
    for (x=0; x<tx; x++)
        dist[x] = (float *)malloc(sizeof(float)*ty);




    pos **pred = (pos **)malloc(sizeof(pos *)*tx);
    for (x=0; x<tx; x++)
        pred[x] = (pos *)malloc(sizeof(pos)*ty);


    etat **tabEtat = (etat **)malloc(sizeof(etat *)*tx);
    for (x=0; x<tx; x++)
        tabEtat[x] = (etat *)malloc(sizeof(etat)*ty);


    dijkstra(j,dist,pred,tabEtat);  // appel a l'algorithme de dijkstra rempli les tableaux dist pred et tabetat

    int i;
    for(i=0; i<j->te.nbEnnemis; i++)       //pour chaque ennemis   peut etre erreur avec -1
    {

        if (ennemisdistance(j,j->te.tabEnnemis[i],dist)==1)//si actif
        {
            {
               //deplacement ennemis vers personnage


                    ennemis *e;
                    e=&j->te.tabEnnemis[i];

                    pos a=pred[e->posX][e->posY];


                    EsetPosition(e, &j->t, a.x, a.y);






            }
        }
    }
//libération des tableaux
    for (y=0; y<tx; y++)
    {
        free(tabEtat[y]);
        free(dist[y]);
        free(pred[y]);
    }
    free(tabEtat);
    free(dist);
    free(pred);

}





int ennemisdistance(jeu *j,ennemis e,float **dist)//renvoie 1 si la  distance rend actif l'ennemi et change l'etat de l'ennemis
{
    float distance;


    // float diagonale;
    //distance à vol d'osieau

    //distance=sqrt(pow(PgetPosX(&(j->p))-EgetPosX(&e),2)-pow(PgetPosY(&(j->p))-EgetPosY(&e),2) ) ;

    //diagonale=sqrt(pow(j->t.dimX,2)+pow(j->t.dimY,2));


    //distance réelle avec les murs

    distance=dist[EgetPosX(&e)][EgetPosY(&e)];

    if (distance < (sqrt(2)*5))
    {
        setEtat(&e,actif);
        return 1;
    }
    else
    {
        setEtat(&e,passif);
        return 0;
    }

}





void dijkstra(jeu *j,float **dist,pos **pred,etat **tabEtat)
{

    const int tx=j->t.dimX;
    const int ty=j->t.dimY;


    int cminx=0,cminy=0;
    int a,b;
//initialisation distance a l'infini  état a blanc   sauf dep  etat gris dist 0
    for( a=0; a<tx; a++)
    {
        for( b=0; b<ty; b++)
        {
            dist[a][b]=FLT_MAX;          // inclure float.h
            pred[a][b].x=-1;
            pred[a][b].y=-1;
            tabEtat[a][b]=blanc;
        }
    }

    dist[j->p.posX][j->p.posY]=0;
    tabEtat[j->p.posX][j->p.posY]=gris;


//boucle  jusqua  que toutes les cases  soient  noir
    int termine=0;

    while(termine==0)
    {
        int i ;
        //trouve la case de dist min
        float distmin=FLT_MAX;

        for(i=0; i<tx; i++)
        {
            for(b=0; b<ty; b++)
            {
                if(tabEtat[i][b]==gris && dist [i][b]<distmin )
                {
                    distmin=dist[i][b];
                    cminx=i;
                    cminy=b;
                }
            }
        }


        //relachement des arcs à partir  de cmin
        int x,y;
        for(y=-1; y<=1; y++)
        {
            for(x=-1; x<=1; x++)
            {

                if((x!=0)||(y!=0))//si c'est un voisin de cmin
                {
                    if(tabEtat[cminx+x][cminy+y]==blanc)//si jamais visité
                    {
                        if(j->t.ter[cminx+x][cminy+y]=='#' )  // si la case est un mur
                        {
                            tabEtat[cminx+x][cminy+y]=noir;
                        }
                        else
                        {

                            if(x!=0 && y!=0)//si c'est une diagonale
                            {
                                dist[cminx+x][cminy+y]=dist[cminx][cminy]+sqrt(2);
                                pred[cminx+x][cminy+y].x=cminx;
                                pred[cminx+x][cminy+y].y=cminy;
                            }
                            else
                            {
                                dist[cminx+x][cminy+y]=dist[cminx][cminy]+1;
                                pred[cminx+x][cminy+y].x=cminx;
                                pred[cminx+x][cminy+y].y=cminy;
                            }

                            tabEtat[cminx+x][cminy+y]=gris;
                        }
                    }

                    if(tabEtat[cminx+x][cminy+y]==gris)//distance déja calculé mais pas completement visité
                    {
                        float couts;
                        if(x!=0 && y!=0)
                        {
                            couts=sqrt(2);
                        }
                        else
                        {
                            couts=1;
                        }

                        if(dist[cminx][cminy]+couts<dist[cminx+x][cminy+y])
                        {
                            dist[cminx+x][cminy+y]=dist[cminx][cminy]+couts;
                            pred[cminx+x][cminy+y].x=cminx;
                            pred[cminx+x][cminy+y].y=cminy;
                        }

                    }
                }//fermeture si voisin cmin
            }//for

        }//for

        tabEtat[cminx][cminy]=noir;

        //vérifie si toute les cases  sont noir
        for(i=0; i<tx; i++)
        {
            for(b=0; b<ty; b++)
            {
                if ((tabEtat[i][b]==blanc) || (tabEtat[i][b]==gris))
                {
                    termine=0;
                }
                else
                {
                    termine=1;
                }
            }
        }


    }//fermeture while


}    //fermeture fonction

